﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AvaliacaoOnline.Data;
using System.Text.RegularExpressions;
using System.Configuration;

namespace AvaliacaoOnline.Model
{
    public class AvaliacaoService
    {

        public List<QuestaoModelo> ParseQuestoes(String questoes)
        {
            //Questoes
            List<QuestaoModelo> lstQuestoes = new List<QuestaoModelo>();

            String PatternNumeroInicio = ConfigurationManager.AppSettings["MarcadorNumeroInicio"];
            String PatternNumeroFim = ConfigurationManager.AppSettings["MarcadorNumeroFim"];

            String PatternQuestaoInicio = ConfigurationManager.AppSettings["MarcadorInicio"] + ConfigurationManager.AppSettings["MarcadorQuestao"];
            String PatternQuestaoFinal = ConfigurationManager.AppSettings["MarcadorFim"];
            String PatternQuestao = String.Format(@"(?<=\{0}).*?(?=\{1})", PatternQuestaoInicio, PatternQuestaoFinal);
            foreach (Match match in Regex.Matches(questoes, PatternQuestao))
            {
                QuestaoModelo questao = new QuestaoModelo();
                questao.Numero = Regex.Matches(match.Value, @"(?<=\[).*?(?=\])")[0].Value.Trim();
                questao.Texto = match.Value.Replace("[" + questao.Numero + "]", String.Empty).Trim();

                //extrai nivel da descricao
                int nivel = 0;
                try
                {
                    Regex nivelRegex = new Regex(@"\(n.vel (\d+)\)$", RegexOptions.IgnoreCase);
                    string aux = nivelRegex.Match(questao.Texto).Groups[1].Value;
                    nivel = int.Parse(aux);

                    questao.Texto = nivelRegex.Replace(questao.Texto, "");
                }
                catch
                {
                    nivel = 0;
                }
                questao.Nivel = nivel;

                lstQuestoes.Add(questao);
            }

            //Opcoes
            List<QuestaoOpcaoModelo> lstOpcoes = new List<QuestaoOpcaoModelo>();

            String PatternOpcaoInicio = ConfigurationManager.AppSettings["MarcadorInicio"] + ConfigurationManager.AppSettings["MarcadorOpcao"];
            String PatternOpcaoFinal = ConfigurationManager.AppSettings["MarcadorFim"];
            String PatternOpcao = String.Format(@"(?<=\{0}).*?(?=\{1})", PatternOpcaoInicio, PatternOpcaoFinal);
            foreach (Match match in Regex.Matches(questoes, PatternOpcao))
            {
                QuestaoOpcaoModelo opcao = new QuestaoOpcaoModelo();
                String NumeroComposto = Regex.Matches(match.Value, @"(?<=\" + PatternNumeroInicio + @").*?(?=\" + PatternNumeroFim + @")")[0].Value;
                opcao.NumeroQuestao = NumeroComposto.Split(',')[0].Trim();
                opcao.Numero = NumeroComposto.Split(',')[1].Trim();
                opcao.Texto = match.Value.Replace(PatternNumeroInicio + NumeroComposto + PatternNumeroFim, String.Empty).Trim();
                lstOpcoes.Add(opcao);
            }

            //Opcoes Corretas
            Dictionary<String, String> dicCorretas = new Dictionary<String, String>();

            String PatternCorretaInicio = ConfigurationManager.AppSettings["MarcadorInicio"] + ConfigurationManager.AppSettings["MarcadorOpcaoCorreta"];
            String PatternCorretaFinal = ConfigurationManager.AppSettings["MarcadorFim"];
            String PatternCorreta = String.Format(@"(?<=\{0}).*?(?=\{1})", PatternCorretaInicio, PatternCorretaFinal);
            foreach (Match match in Regex.Matches(questoes, PatternCorreta))
            {
                String Numero = Regex.Matches(match.Value, @"(?<=\" + PatternNumeroInicio + @").*?(?=\" + PatternNumeroFim + @")")[0].Value;
                String Correta = match.Value.Replace(PatternNumeroInicio + Numero + PatternNumeroFim, String.Empty);

                dicCorretas.Add(Numero.Trim(), Correta.Trim());
            }

            //Define correta na lista de opcoes
            foreach (string key in dicCorretas.Keys)
            {
                QuestaoOpcaoModelo o = lstOpcoes.Where(c => key == c.NumeroQuestao && dicCorretas[key] == c.Numero).FirstOrDefault();
                if (o != null)
                    o.Correta = true;
            }

            //Une as coleções na lista de questoes.
            lstQuestoes = lstQuestoes.GroupJoin(lstOpcoes,
                                                q => q.Numero,
                                                o => o.NumeroQuestao,
                                                (q, o) => { q.Opcoes = o.ToList(); return q; }
                                                ).ToList();

            return lstQuestoes;
        }

        public string GetImagemFundoURL(string serverPath, int idAvaliacao)
        {
            AvaliacaoRepository repository = new AvaliacaoRepository();
            Avaliacao avaliacao = repository.GetAvaliacao(idAvaliacao);

            if (avaliacao == null)
                return "";

            if (String.IsNullOrWhiteSpace(avaliacao.ImagemFundo))
                return "";

            return UploadService.GetFileURL(serverPath, avaliacao.ImagemFundo, avaliacao.IdCliente, idAvaliacao);
        }

        public string GetArquivoEstiloURL(string serverPath, int idAvaliacao)
        {
            AvaliacaoRepository repository = new AvaliacaoRepository();
            Avaliacao avaliacao = repository.GetAvaliacao(idAvaliacao);

            if (avaliacao == null)
                return "";

            if (String.IsNullOrWhiteSpace(avaliacao.ImagemFundo))
                return "";

            return UploadService.GetFileURL(serverPath, avaliacao.ArquivoEstilo, avaliacao.IdCliente, idAvaliacao);
        }

        public void IniciarAvaliacao(int idUsuario, int idAvaliacao)
        {
            AvaliacaoOnlineContext context = AvaliacaoOnlineContext.GetContext();
            var avalUsuario = context.AvaliacaoUsuario.Where(c => c.IdUsuario == idUsuario && c.IdAvaliacao == idAvaliacao).First();

            if (!avalUsuario.DataInicial.HasValue)
            {
                avalUsuario.DataInicial = DateTime.Now.NormalizeDate();

                context.SaveChanges();
            }
        }

        public void FinalizarAvaliacao(int idUsuario, int idAvaliacao)
        {
            AvaliacaoOnlineContext context = AvaliacaoOnlineContext.GetContext();
            var avalUsuario = context.AvaliacaoUsuario.Where(c => c.IdUsuario == idUsuario && c.IdAvaliacao == idAvaliacao).First();

            if (!avalUsuario.DataFinal.HasValue)
            {
                avalUsuario.DataFinal = DateTime.Now.NormalizeDate();
                avalUsuario.Concluido = "S";
                avalUsuario.QuantidadeSegundos = Convert.ToInt32(avalUsuario.DataFinal.Value.Subtract(avalUsuario.DataInicial.Value).TotalSeconds);

                context.SaveChanges();
            }
        }

        public void ResponderQuestao(int idUsuario, int idAvaliacao, int idQuestao, int numeroAlternativa, out bool concluida)
        {
            concluida = false;
            AvaliacaoOnlineContext context = AvaliacaoOnlineContext.GetContext();
            var avalUsuario = context.AvaliacaoUsuario.Include("Avaliacao").Include("Respostas").Where(c => c.IdUsuario == idUsuario && c.IdAvaliacao == idAvaliacao).First();

            List<Resposta> lstResposta = avalUsuario.Respostas.Where(c => c.IdQuestao == idQuestao).ToList();

            //avaliacao limitada por tempo e ja foi respondida
            if (avalUsuario.Avaliacao.LimiteTempo.ToUpper() == "S" && lstResposta.Count > 0)
                return;

            //avaliacao ja concluida
            if (avalUsuario.Concluido.ToUpper() == "S")
            {
                concluida = true;
                return;
            }

            Resposta respostaEscolhida = lstResposta.Where(c => c.NumeroAlternativa == numeroAlternativa).FirstOrDefault();
            if (respostaEscolhida == null)
            {
                respostaEscolhida = new Resposta()
                    {
                        IdAvaliacao = idAvaliacao,
                        IdQuestao = idQuestao,
                        IdUsuario = idUsuario,
                        NumeroAlternativa = numeroAlternativa
                    };
                respostaEscolhida.Data = DateTime.Now.NormalizeDate();
                respostaEscolhida.NumeroAlternativa = numeroAlternativa;
                avalUsuario.Respostas.Add(respostaEscolhida);
            }

            foreach (Resposta respostaAnterior in lstResposta.Where(c => c.NumeroAlternativa != numeroAlternativa))
                avalUsuario.Respostas.Remove(respostaAnterior);

            context.SaveChanges();
        }
    }


    public static class AvaliacaoServiceMethods
    {
        public static DateTime NormalizeDate(this DateTime date)
        {
            string aux = ConfigurationManager.AppSettings["DiferencaFusoHorario"];
            if (!String.IsNullOrWhiteSpace(aux))
            {
                double auxInt = 0;
                double.TryParse(aux, out auxInt);

                return date.AddHours(auxInt);
            }
            else
            {
                return date;
            }
        }
    }

    public class QuestaoModelo
    {
        public QuestaoModelo()
        {
            this.Opcoes = new List<QuestaoOpcaoModelo>();
        }

        public String Numero { get; set; }
        public String Texto { get; set; }
        public Int32 Nivel { get; set; }
        public List<QuestaoOpcaoModelo> Opcoes { get; set; }
    }
    public class QuestaoOpcaoModelo
    {
        public QuestaoOpcaoModelo()
        {
            this.Correta = false;
        }
        public String NumeroQuestao { get; set; }
        public String Numero { get; set; }
        public String Texto { get; set; }
        public Boolean Correta { get; set; }
    }
}
